package com.artevivo.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.artevivo.dao.interfaces.IGenericDAO;
import com.artevivo.utilidades.ILogService;
import com.artevivo.utilidades.Log4JavaServiceImpl;

/**
 * Clase para control de datos de manera generica.
 * 
 * @param <T>
 *            the generic type
 * @param <ID>
 *            the generic type
 */
@Repository
public abstract class AbstractDAO<T, ID extends Serializable> extends HibernateDaoSupport implements IGenericDAO<T, ID> {

    /** The Constant FROM. */
    private static final String FROM = "from ";

    /** The persistent class. */
    protected Class persistentClass;

    /** The log service. */
    protected ILogService logService = new Log4JavaServiceImpl();

    /** The session. */
    protected Session session;

    /** The session factory. */
    @SuppressWarnings("unchecked")
    @Autowired
    public AbstractDAO(SessionFactory sessionFactory) {
        super.setSessionFactory(sessionFactory);
        this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    public AbstractDAO() {
    }

    public Session getCurrentSession() {
        return this.getSessionFactory().getCurrentSession();
    }

    /**
     * Gets the persistent class.
     * 
     * @return the persistent class
     */
    public Class getPersistentClass() {
        return persistentClass;
    }

    /**
     * {@inheritDoc}
     * 
     * @see com.psiject.dao.interfaces.IGenericDAO#findById(ID)
     */
    @Override
    @Transactional(readOnly = true)
    public T findById(ID id) throws Exception {
        T entity = null;
        try {
            Session sesion = getCurrentSession();
            entity = (T) sesion.get(getPersistentClass(), id);
        } catch (Exception ex) {
            throw new Exception(ex.getMessage(), ex);
        }
        return entity;
    }

    /**
     * {@inheritDoc}
     * 
     * @see com.psiject.dao.interfaces.IGenericDAO#findByIdWithoutClose(ID)
     */
    @Override
    @Transactional(readOnly = true)
    public T findByIdWithoutClose(ID id) throws Exception {
        T entity = null;
        try {
            Session sesion = getCurrentSession();
            entity = (T) sesion.get(getPersistentClass(), id);
        } catch (Exception ex) {
            throw new Exception(ex.getMessage(), ex);
        }
        return entity;
    }

    /**
     * {@inheritDoc}
     * 
     * @see com.psiject.dao.interfaces.IGenericDAO#findAll()
     */
    @Override
    @Transactional(readOnly = true)
    public List<T> findAll() throws Exception {
        List<T> result = null;
        try {
            Session sesion = getCurrentSession();
            final Query query = sesion.createQuery(FROM + persistentClass.getName());
            result = query.list();
        } catch (Exception ex) {
            throw new Exception(ex.getMessage(), ex);
        }
        return result;
    }

    /**
     * {@inheritDoc}
     * 
     * @see com.psiject.dao.interfaces.IGenericDAO#deleteAll()
     */
    @Override
    @Transactional
    public void deleteAll() throws Exception {
        try {
            Session sesion = getCurrentSession();
            List<T> result = (List<T>) sesion.get(getPersistentClass(), null);
            if (result != null) {
                for (T obj : result) {
                    this.delete(obj);
                }
            }
        } catch (Exception e) {
            throw new Exception(e.getMessage(), e);
        }
    }

    /**
     * {@inheritDoc}
     * 
     * @see com.psiject.dao.interfaces.IGenericDAO#insert(T)
     */
    @Override
    @Transactional
    public void insert(T entity) throws Exception {
        try {
            Session sesion = getCurrentSession();
            sesion.saveOrUpdate(entity);
        } catch (Exception e) {
            throw new Exception(e.getMessage(), e);
        }
    }

    /**
     * {@inheritDoc}
     * 
     * @see com.psiject.dao.interfaces.IGenericDAO#insertList(java.util.List)
     */
    @Override
    @Transactional
    public void insertList(List<T> entity) throws Exception {
        try {
            Session sesion = getCurrentSession();
            sesion.saveOrUpdate(entity);
        } catch (Exception e) {
            throw new Exception(e.getMessage(), e);
        }
    }

    /**
     * {@inheritDoc}
     * 
     * @see com.psiject.dao.interfaces.IGenericDAO#update(T)
     */
    @Override
    @Transactional
    public T update(T entity1) throws Exception {
        T entity = entity1;
        try {
            Session sesion = getCurrentSession();
            entity = (T) sesion.merge(entity);
            getCurrentSession().flush();
        } catch (Exception e) {
            throw new Exception(e.getMessage(), e);
        }
        return entity;
    }

    /**
     * {@inheritDoc}
     * 
     * @see com.psiject.dao.interfaces.IGenericDAO#updateList(java.util.List)
     */
    @Override
    @Transactional
    public List<T> updateList(List<T> entity1) throws Exception {
        List<T> entity = entity1;
        try {
            Session sesion = getCurrentSession();
            entity = (List<T>) sesion.merge(entity);
            getCurrentSession().flush();
        } catch (Exception e) {
            throw new Exception(e.getMessage(), e);
        }
        return entity;
    }

    /**
     * {@inheritDoc}
     * 
     * @see com.psiject.dao.interfaces.IGenericDAO#saveOrUpdate(T)
     */
    @Override
    @Transactional
    public void saveOrUpdate(T entity) throws Exception {
        try {
            Session sesion = getCurrentSession();
            sesion.saveOrUpdate(entity);
        } catch (Exception e) {
            throw new Exception(e.getMessage(), e);
        }
    }

    /**
     * {@inheritDoc}
     * 
     * @see com.psiject.dao.interfaces.IGenericDAO#delete(T)
     */
    @Override
    @Transactional
    public void delete(T entity) throws Exception {
        try {
            Session sesion = getCurrentSession();
            sesion.delete(entity);
        } catch (Exception e) {
            throw new Exception(e.getMessage(), e);
        }
    }

    /**
     * {@inheritDoc}
     * 
     * @see com.psiject.dao.interfaces.IGenericDAO#deleteList(java.util.List)
     */
    @Override
    @Transactional
    public void deleteList(List<T> entity) throws Exception {
        try {
            Session sesion = getCurrentSession();
            sesion.delete(entity);
        } catch (Exception e) {
            throw new Exception(e.getMessage(), e);
        }
    }

    /**
     * Gets the log service sae.
     * 
     * @return the logServiceSae
     */
    public ILogService getLogServiceSae() {
        return logService;
    }

    /**
     * Sets the log service.
     * 
     * @param logService
     *            the new log service
     */
    public void setLogServiceSae(ILogService logService) {
        this.logService = logService;
    }

}
